﻿/*
 * User: dvetters
 * Date: 7/28/2010
 * Time: 9:36 AM
 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

using Declarations;

namespace Echium2
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class MainForm : Form
	{
		public MainForm()
		{
			InitializeComponent();
			#if DEBUG
			this.Text += " DEBUG BUILD";
			#endif
			MediaGlobals.player.Events.MediaEnded += new EventHandler(MediaGlobals_player_Events_MediaEnded);
			MediaGlobals.player.Events.TimeChanged += new EventHandler<TimeChangedEventArgs>(MediaGlobals_player_Events_TimeChanged);
			mediaInfoPane1.PositionManuallyChangedEvent += new EventHandler<EventArgs<double>>(mediaInfoPane1_PositionManuallyChangedEvent);
			mediaList.Columns[0].Width = mediaList.Width / 3;
			mediaList.Columns[1].Width = mediaList.Width / 4;
			mediaList.Columns[2].Width = mediaList.Width / 4;
			mediaSourceTreeView1.Nodes[0].Tag = MediaGlobals.MainLibrary;
			foreach (EchiumPlaylist playlist in MediaGlobals.MainLibrary.Playlists.Values)
			{
				mediaSourceTreeView1.AddItem(playlist.PlaylistName, ItemType.Playlist, 0);
			}
			foreach (EchiumTrack track in MediaGlobals.MainLibrary.Tracks.Values)
			{
				mediaList.AddItem(track);
			}
		}

		private void mediaInfoPane1_PositionManuallyChangedEvent(object sender, EventArgs<double> e)
		{
			this.mediaInfoPane1.Position = e.Arg;
			MediaGlobals.player.Time = (long)e.Arg;
		}

		private void MediaGlobals_player_Events_TimeChanged(object sender, TimeChangedEventArgs e)
		{
			this.mediaInfoPane1.Position = e.NewTime;
		}

		private void MediaGlobals_player_Events_MediaEnded(object sender, EventArgs e)
		{
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(MediaGlobals_player_Events_MediaEnded), new object[]{this, e});
            }
            else
            {
                NextSong();
            }
		}
		
		private void RepeatBtnClicked(object sender, EventArgs e)
		{
			if (repeatBtn.CheckState == CheckState.Indeterminate)
			{
				repeatBtn.ImageIndex = 1;
			}
			else
			{
				repeatBtn.ImageIndex = 0;
			}
		}
		
		private void PlayPauseBtnClick(object sender, EventArgs e)
		{
			if (MediaGlobals.player.State == MediaState.Playing)
			{
				MediaGlobals.player.Pause();
				playPauseBtn.CheckState = CheckState.Unchecked;
			}
			else if (MediaGlobals.player.State == MediaState.Paused)
			{
				MediaGlobals.player.Play();
				playPauseBtn.CheckState = CheckState.Checked;
			}
			else
			{
				EchiumTrack track = ((MediaListItem)mediaList.Items[0]).TrackItem;
				MediaGlobals.CurrentPlaylist = BuildQuicklist(mediaList, ((MediaListItem)mediaList.Items[0]));
				PlayTrack(track);
			}
		}
		
		private void PrevBtnClick(object sender, EventArgs e)
		{
			PreviousSong();
		}
		
		private void StopBtnClick(object sender, EventArgs e)
		{
			MediaGlobals.player.Stop();
			playPauseBtn.CheckState = CheckState.Unchecked;
			mediaInfoPane1.SetMediaInfo(null);
		}
		
		private void NextBtnClick(object sender, EventArgs e)
		{
			NextSong();
		}
		
		private void MediaSourceTreeView1NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
		{
			mediaList.Items.Clear();
			if (e.Node.Parent == null) //library node
			{
				foreach (EchiumTrack track in ((EchiumLibrary)e.Node.Tag).Tracks.Values)
				{
					mediaList.AddItem(track);
				}
			}
			else //playlist node
			{
				EchiumPlaylist playlist = (EchiumPlaylist)e.Node.Tag;
				foreach (int id in playlist.TrackIDs)
				{
					mediaList.AddItem(((EchiumLibrary)e.Node.Parent.Tag).Tracks[id]);
				}
			}
		}
		
		private void PlayQueueListView1ItemActivate(object sender, EventArgs e)
		{
			ListViewItem itemTemp =  playQueueListView1.SelectedItems[0];
			playQueueListView1.Items.Insert(0, itemTemp);
			playQueueListView1.Items.RemoveAt(itemTemp.Index+1);
			playQueueListView1.Items[0].Selected = true;
			NextSong();
		}
		
		private void MediaListItemActivate(object sender, EventArgs e)
		{
			EchiumTrack track = ((MediaListItem)mediaList.SelectedItems[0]).TrackItem;
			MediaGlobals.CurrentPlaylist = BuildQuicklist(mediaList, ((MediaListItem)mediaList.SelectedItems[0]));
			PlayTrack(track);
		}
		
		
		private EchiumPlaylist BuildQuicklist(MediaList source)
		{
			if (this.shuffleBtn.CheckState == CheckState.Checked)
			{
				Random rand = new Random();
				return BuildQuicklist(source, (MediaListItem)source.Items[rand.Next(source.Items.Count-1)]);
			}
			else
			{
				return BuildQuicklist(source, (MediaListItem)source.Items[0]);
			}
		}
		
		private EchiumPlaylist BuildQuicklist(MediaList source, MediaListItem firstSong)
		{
			EchiumPlaylist playlist = new EchiumPlaylist(MediaGlobals.MainLibrary, "QuickList");
			if (this.shuffleBtn.CheckState == CheckState.Checked)
			{
				Random rand = new Random();
				playlist.TrackIDs.Add(firstSong.TrackItem.ID);
				foreach (MediaListItem item in source.Items)
				{
					if (item.Index == firstSong.Index) continue;
					playlist.TrackIDs.Insert(rand.Next(1, playlist.TrackIDs.Count), item.TrackItem.ID);
				}
			}
			else
			{
				int idx = source.Items.IndexOf(firstSong);
				for (;idx < source.Items.Count; idx++)
				{
					playlist.TrackIDs.Add(((MediaListItem)source.Items[idx]).TrackItem.ID);
				}
			}
			return playlist;
		}
		
		private void NextSong()
		{
			if (MediaGlobals.CurrentPlaylist != null)
			{
				if (MediaGlobals.PlayingFromQueue)
					playQueueListView1.Items.RemoveAt(0);
				if (playQueueListView1.Items.Count >= 1)
				{
					MediaGlobals.PlayingFromQueue = true;
					playQueueListView1.Items[0].Selected = true;
                    PlayTrack((EchiumTrack)playQueueListView1.Items[0].Tag);
				}
				else
				{
                    MediaGlobals.PlayingFromQueue = false;
					int currentIndex = MediaGlobals.CurrentPlaylist.TrackIDs.IndexOf(MediaGlobals.CurrentTrack.ID);
					//check for repeating
					if (currentIndex+1 >= MediaGlobals.CurrentPlaylist.TrackIDs.Count)
					{
						if (repeatBtn.CheckState == CheckState.Checked) //repeat all
							currentIndex = -1;
						else if (repeatBtn.CheckState == CheckState.Indeterminate) //repeat 1
							currentIndex--;
						else
						{
							MediaGlobals.player.Stop();
							playPauseBtn.CheckState = CheckState.Unchecked;
							mediaInfoPane1.SetMediaInfo(null);
							return;
						}
					}
					PlayTrack(MediaGlobals.CurrentPlaylist.ParentLibrary.Tracks[MediaGlobals.CurrentPlaylist.TrackIDs[currentIndex+1]]);
					SelectSongInList(MediaGlobals.CurrentPlaylist.ParentLibrary.Tracks[MediaGlobals.CurrentPlaylist.TrackIDs[currentIndex+1]]);
				}
			}
			else
			{
				if (mediaList.SelectedItems.Count >= 1)
				{
					int idx = mediaList.SelectedItems[0].Index;
					mediaList.SelectedItems[0].Selected = false;
					if (idx < mediaList.Items.Count)
					{
						mediaList.Items[idx+1].Selected = true;
					}
					else if (repeatBtn.CheckState == CheckState.Checked)
					{
						mediaList.Items[0].Selected = true;
					}
				}
				else
					mediaList.Items[0].Selected = true;
			}
		}
		
		private void PreviousSong()
		{
			if (MediaGlobals.CurrentPlaylist != null)
			{
				int currentIndex = MediaGlobals.CurrentPlaylist.TrackIDs.IndexOf(MediaGlobals.CurrentTrack.ID);
				if (MediaGlobals.PlayingFromQueue)
				{
					playQueueListView1.Items.RemoveAt(0);
					MediaGlobals.PlayingFromQueue = false;
					currentIndex++;
				}
				PlayTrack(MediaGlobals.CurrentPlaylist.ParentLibrary.Tracks[MediaGlobals.CurrentPlaylist.TrackIDs[currentIndex-1]]);
				//highlight new song in list
				if (!MediaGlobals.PlayingFromQueue)
					SelectSongInList(MediaGlobals.CurrentPlaylist.ParentLibrary.Tracks[MediaGlobals.CurrentPlaylist.TrackIDs[currentIndex-1]]);
			}
			else
			{
				if (mediaList.SelectedItems.Count >= 1)
				{
					int idx = mediaList.SelectedItems[0].Index;
					mediaList.SelectedItems[0].Selected = false;
					if (idx < mediaList.Items.Count)
					{
						mediaList.Items[idx-1].Selected = true;
					}
					else if (repeatBtn.CheckState == CheckState.Checked)
					{
						mediaList.Items[mediaList.Items.Count-1].Selected = true;
					}
				}
				else
					mediaList.Items[mediaList.Items.Count-1].Selected = true;
			}
		}
		
		private void PlayTrack(EchiumTrack track) //WARNING: this method is full of fugly hacks to try and deal with a race condition with the VLC API/wrapper
		{
			IMedia media = MediaGlobals.factory.CreateMedia<IMedia>(track.Location);
			MediaGlobals.player.Open(media);
			MediaGlobals.player.Play();
			while (media.State != MediaState.Error && (media.State == MediaState.NothingSpecial || media.State == MediaState.Opening || media.Duration == 0)){System.Threading.Thread.Sleep(10);} //let the library load the file
			SelectSongInList(track);
			if (media.State == MediaState.Playing) //loaded file (hopefully)
			{
				track.ParentLibrary.Tracks[track.ID].Duration = media.Duration;
				track.ParentLibrary.Tracks[track.ID].Title = media.GetMetaData(MetaDataType.Title);
				track.ParentLibrary.Tracks[track.ID].Artist = media.GetMetaData(MetaDataType.Artist);
				track.ParentLibrary.Tracks[track.ID].Album = media.GetMetaData(MetaDataType.Album);
				track = track.ParentLibrary.Tracks[track.ID];
				track.ParentLibrary.SaveLibrary();
				((MediaListItem)mediaList.SelectedItems[0]).TrackItem = track;
				TimeSpan duration = TimeSpan.FromMilliseconds(track.Duration);
				string time = ((duration.Hours > 0)?duration.Hours + ":":"") + ((duration.Minutes > 9)?""+duration.Minutes:((duration.Hours > 0)?"0":"")+duration.Minutes) + ":" + ((duration.Seconds > 9)?""+duration.Seconds:"0"+duration.Seconds);
				((MediaListItem)mediaList.SelectedItems[0]).SubItems[0].Text = track.Title;
				((MediaListItem)mediaList.SelectedItems[0]).SubItems[1].Text = track.Artist;
				((MediaListItem)mediaList.SelectedItems[0]).SubItems[2].Text = track.Album;
				((MediaListItem)mediaList.SelectedItems[0]).SubItems[3].Text = time;
				MediaGlobals.CurrentTrack = track;
				playPauseBtn.CheckState = CheckState.Checked;
				mediaInfoPane1.SetMediaInfo(track);
				((MediaListItem)mediaList.SelectedItems[0]).BackColor = Color.White;
				((MediaListItem)mediaList.SelectedItems[0]).ToolTipText = "";
			}
			else if (media.State == MediaState.Error)
			{
				MediaGlobals.CurrentTrack = track;
				((MediaListItem)mediaList.SelectedItems[0]).BackColor = Color.Red;
				((MediaListItem)mediaList.SelectedItems[0]).ToolTipText = "Unable to open file";
				if (repeatBtn.CheckState != CheckState.Indeterminate) NextSong();
			}
			else //shouldn't get here
			{
				MessageBox.Show( media.State.ToString(), "WTF");
			}
		}
		
		private void SelectSongInList(EchiumTrack track)
		{
			if (mediaList.SelectedItems.Count <= 1)
			{
				if (mediaList.SelectedItems.Count > 0) mediaList.SelectedItems[0].Selected = false;
				foreach (MediaListItem item in mediaList.Items)
				{
					if (item.TrackItem.ID == track.ID)
					{
						//item.Selected = true; //TODO: This isn't working, don't know why.
                        mediaList.Items[item.Index].Selected = true;
						break;
					}
				}
			}
		}
		
		private void SetMediaListCtxDefault()
		{
			this.mediaListCtxMenu.Items.Clear();
			this.mediaListCtxMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
									this.addSongToolStripMenuItem});
			this.mediaList.ContextMenuStrip = mediaListCtxMenu;
		}
		
		private void MediaListMouseDown(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right)
			{
				SetMediaListCtxDefault();
				MediaListItem item = (MediaListItem)mediaList.GetItemAt(e.X, e.Y);
				if (item != null)
				{
					if (mediaList.SelectedItems.Count > 0) mediaList.SelectedItems[0].Selected = false;
					item.Selected = true;
					ToolStripMenuItem addToQueueMenuItem = new ToolStripMenuItem("Add to Queue", null, new EventHandler(MediaList_AddToQueue));
					ToolStripMenuItem showInBrowserMenuItem = new ToolStripMenuItem("Show In Browser", null, new EventHandler(MediaList_ShowInBrowser));
					ToolStripMenuItem exportMenuItem = new ToolStripMenuItem("Export To...", null, new EventHandler(MediaList_ExportTo));
					ToolStripMenuItem removeSongMenuItem = new ToolStripMenuItem("Remove From Library", null, new EventHandler(MediaList_RemoveFromLibrary));
					if (MediaGlobals.MainLibrary.Filename != item.TrackItem.ParentLibrary.Filename) removeSongMenuItem.Enabled = false;
					//if (this.mediaSourceTreeView1.SelectedNode.Index != 0) removeSongMenuItem.Enabled = false;
					mediaListCtxMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
									this.toolStripSeparator1, showInBrowserMenuItem, addToQueueMenuItem, exportMenuItem, removeSongMenuItem});
				}
			}
		}
		
		private void MediaList_AddToQueue(object sender, EventArgs e)
		{
			MediaListItem item = (MediaListItem)mediaList.SelectedItems[0];
			if (item != null)
			{
				playQueueListView1.AddToQueue(item.TrackItem);
			}
		}
		
		private void MediaList_ShowInBrowser(object sender, EventArgs e)
		{
			MediaListItem item = (MediaListItem)mediaList.SelectedItems[0];
			if (item != null)
			{
				System.Diagnostics.Process.Start("explorer.exe", Path.GetDirectoryName(item.TrackItem.Location));
			}
		}
		
		private void MediaList_ExportTo(object sender, EventArgs e)
		{
			MediaListItem item = (MediaListItem)mediaList.SelectedItems[0];
			if (item != null)
			{
				SaveFileDialog saveDialog = new SaveFileDialog();
				saveDialog.Filter = "|*" + Path.GetExtension(item.TrackItem.Location);
				saveDialog.FileName = item.TrackItem.Artist + " - " + item.TrackItem.Title + Path.GetExtension(item.TrackItem.Location);
				if (saveDialog.ShowDialog() == DialogResult.OK)
				{
					File.Copy(item.TrackItem.Location, saveDialog.FileName);
				}
			}
		}
		
		private void MediaList_RemoveFromLibrary(object sender, EventArgs e)
		{
			MediaListItem item = (MediaListItem)mediaList.SelectedItems[0];
			if (item != null)
			{
				MediaGlobals.MainLibrary.Tracks.Remove(item.TrackItem.ID);
				mediaList.Items.Remove(item);
			}
		}
		
		private void MediaList_AddSong(object sender, EventArgs e)
		{
			OpenFileDialog openDialog = new OpenFileDialog();
			if (openDialog.ShowDialog() == DialogResult.OK)
			{
				EchiumTrack track = MediaGlobals.MainLibrary.NewTrack(Path.GetFileName(openDialog.FileName), openDialog.FileName, 1);
				mediaList.AddItem(track);
			}
		}

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MediaGlobals.player != null) MediaGlobals.player.Stop();
        }
	}
}
